package com.passer.toolbox.common.network;

import com.passer.toolbox.common.core.util.CmdUtils;
import com.passer.toolbox.common.network.util.NetworkUtils;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 局域网可访问IP查找
 */
@Slf4j
public class LANIpFind {

    public List<String> find() {
        Optional<Inet4Address> localIp4Address;
        try {
            localIp4Address = NetworkUtils.getLocalIp4Address();
        } catch (SocketException e) {
            log.error("【LANIpFind】获取本机IP地址失败：{}", e.getMessage());
            return new ArrayList<>();
        }
        if (!localIp4Address.isPresent()) {
            log.error("【LANIpFind】未获取到本机IP地址");
            return new ArrayList<>();
        }
        String hostAddress = localIp4Address.get().getHostAddress();
        String substring = hostAddress.substring(0, hostAddress.lastIndexOf(".") + 1);
        List<String> ipList = new ArrayList<>();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 8, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        for (int i = 1; i < 255; i+= 50) {
            int finalI = i;
            threadPoolExecutor.execute(() -> findByInetAddress(ipList, substring, finalI, finalI < 250 ? 50 : 4));
        }
        threadPoolExecutor.shutdown();
        try {
            if (!threadPoolExecutor.awaitTermination(15, TimeUnit.MINUTES)) {
                log.error("【LANIpFind】线程池等待失败");
                threadPoolExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            log.error("【LANIpFind】线程池等待异常：{}", e.getMessage());
            threadPoolExecutor.shutdownNow();
        }
        return ipList;
    }

    public void findByPing(List<String> ipList, String localIpSub, int start, int num) {
        for (int i = start; i < start + num; i++) {
            String ip = localIpSub + i;
            log.info("ping局域网IP：{}", ip);
            try {
                if (CmdUtils.ping(ip)) {
                    ipList.add(ip);
                }
            } catch (IOException e) {
                log.error("ping {} 失败：{}", ip, e.getMessage());
            }
        }
    }


    public void findByInetAddress(List<String> ipList, String localIpSub, int start, int num) {
        for (int i = start; i < start + num; i++) {
            String ip = localIpSub + i;
            log.info("测试访问局域网IP：{}", ip);
            try {
                if (InetAddress.getByName(ip).isReachable(5000)) {
                    ipList.add(ip);
                }
            } catch (IOException e) {
                log.error("测试访问 {} 失败：{}", ip, e.getMessage());
            }
        }
    }
}
